/*************************Line.cpp***********************
 * this file is the implementing file for Lines
 * author: Zebras Wen
 * date: 2012.11.04
 * version: 0.01
 * history:
 * copyLeft:
 *   all rights are under the GPL v3.0
 *********************************************************/

#include "Line.h"
#include "Station.h"
#include<list>
#include<algorithm>
#include<iostream>

using namespace std;

/**
  * constructor of class line
  * @param void
  * @return no return
  * @author Zebras Wen
  */
Line::Line(void):lineNo_(-1)
{
}

/**
  * copy constructor of class line
  * @param const Line& line, a copy construtor
  * @return no return
  * @author Zebras Wen
  */
Line::Line(const Line& line)
{
    this->line_ = line.line_;
}

/**
  * destructor
  * @param void
  * @return no return
  * @author Zebras Wen
  */
Line::~Line(void)
{
}

/**
  * overloading of operator =
  * @param const Line &line,
  * @return Line&, in order to continue  assignment
  * @author Zebras Wen
  */
Line& Line::operator=(const Line& line)
{
    this->line_ = line.line_;
    this->lineNo_ = line.lineNo_;
    return *this;
}

/**
  * add a station to the line, at the end
  * @param Station *station, a pointer of a station
  * @return void
  * @author Zebras Wen
  */
void Line::addStationEnd(Station *station)
{
    list<Station*>::iterator iteB = line_.begin();
    list<Station*>::iterator iteE = line_.end();
    if (find(iteB,iteE,station) == iteE)
    {
        this->line_.push_back(station);
    }
}

/**
  * add a station to the line, at the begin
  * @param Station *station, a pointer of a station
  * @return void
  * @author Zebras Wen
  */
void Line::addStationBegin(Station* station)
{
    list<Station*>::iterator iteB = line_.begin();
    list<Station*>::iterator iteE = line_.end();
    if (find(iteB,iteE,station) == iteE)
    {
        this->line_.push_front(station);
    }
}

/**
  * add a station to the line, begin the specified station
  * @param Station *station, a pointer of a station
  * @return void
  * @author Zebras Wen
  */
void Line::addStationBefore(Station* station, Station *beforeStation)
{
    list<Station*>::iterator iteB = line_.begin();
    list<Station*>::iterator iteE = line_.end();
    list<Station*>::iterator iteT;
    if (beforeStation &&(iteT =  find(iteB,iteE,beforeStation) )!= iteE)
    {
        this->line_.insert(iteT, station);
    }
}

/**
  * add a station to the line, begin the specified station
  * @param const string&, name of a station
  * @return void
  * @author Zebras Wen
  */
void Line::addStationBefore(Station* station, const string &beforeStation)
{
    Station *stationFound = findStation(beforeStation);
    list<Station*>::iterator iteB = line_.begin();
    list<Station*>::iterator iteE = line_.end();
    list<Station*>::iterator iteT;
    if (stationFound &&(iteT = find(iteB, iteE, stationFound) )!= iteE)
    {
        this->line_.insert(iteT, station);
    }
}

/**
  * add a station to the line, after the specified station
  * @param Station *station, a pointer of a station
  * @return void
  * @author Zebras Wen
  */
void Line::addStationAfter(Station* station, Station *afterStation)
{
    list<Station*>::iterator iteB = line_.begin();
    list<Station*>::iterator iteE = line_.end();
     list<Station*>::iterator iteT;
    if (afterStation &&(iteT =  find(iteB, iteE, afterStation) )!= iteE)
    {
        this->line_.insert(++iteT, station);
    }
}

/**
  * add a station to the line, after the specified station
  * @param const string&, name of a station
  * @return void
  * @author Zebras Wen
  */
void Line::addStationAfter(Station* station, const string &afterStation)
{
    Station* stationFound = findStation(afterStation);
    list<Station*>::iterator iteB = line_.begin();
    list<Station*>::iterator iteE = line_.end();
     list<Station*>::iterator iteT;
    if (stationFound && (iteT = find(iteB,iteE,stationFound) )!= iteE)
    {
        this->line_.insert(++iteT, station);
    }
}


/**
  * this function delete the specified station according
  * to the pointer to a station
  * @param station a pointer of a station
  * @return void
  * @author Zebras Wen
  */
void Line::delStations(Station *station)
{
    list<Station*>::iterator iteB = line_.begin();
    list<Station*>::iterator iteE = line_.end();
    list<Station*>::iterator iteT;
    if ((iteT = find(iteB,iteE,station)) != iteE)
    {
        this->line_.erase(iteT);
    }
}

/**
  * this function delete the specified station according
  * to the pointer to a station.
  * @param const string &stationName, name of a station.
  * @return void
  * @author Zebras Wen
  */
void Line::delStations(const string &stationName)
{
    Station* station = findStation(stationName);
    if (station)
    {
       line_.erase(find(line_.begin(), line_.end(), station));
    }

}

/**
  * find a station according to certain station pointer.
  * @param Station *station, a pointer to a station.
  * @return Station*, pointer to the station found.
  * @author Zebras Wen
  */
Station* Line::findStation(Station* station)
{
    list<Station*>::iterator iteB = line_.begin();
    list<Station*>::iterator iteE = line_.end();
    return *(find(iteB, iteE, station));
}

/**
  * this function delete the specified station according
  * to the pointer to a station.
  * @param const string &name name of a station.
  * @return void
  * @author Zebras Wen
  */
Station* Line::findStation(const string& name)
{
    list<Station*>::iterator iteB = line_.begin();
    list<Station*>::iterator iteE = line_.end();
    for (; iteB != iteE; ++iteB)
    {
        if (0 == name.compare((*iteB)->getStationName()))
        {
            return *iteB;
        }
    }
    return 0;
}

/**
  * overloading of operator <<
  * @param ostream& os, output stream
  * @param Line &line, line to output
  * @return ostream&, in order to continue output
  * @author Zebras Wen
  */
ostream& operator<<(ostream& os, Line &line)
{
    list<Station*>::iterator iteB = line.line_.begin();
    list<Station*>::iterator iteE = line.line_.end();
    for (;; )
    {
        os<<(*iteB)->getStationName();
        ++iteB;
        if ( iteB != iteE)
        {
            os<<"->";
        }
        else
        {
            break;
        }
    }
    // os<<endl;
    return os;
}

/**
  * print line function, can be directed to different output stream
  * @param osstream &os, output stream selection
  * @return void
  * @author Zebras Wen
  */
void Line::printLine(ostream& os)
{
    ::operator<<(os, *this);
}

